home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1995 April / Internet Tools.iso / ip / nfs / nfstrace.shar.Z / nfstrace.shar / nfstrace.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-02-06  |  12.7 KB  |  776 lines

  1. /*
  2.  * nfstrace main module
  3.  * release 0.9
  4.  *
  5.  * Copyright 1991 Matt Blaze.
  6.  * May be freely reproduced for non-commerical use.
  7.  * All other rights, including use for direct commerical advantage or
  8.  * use in a commerical product, are reserved by the author.
  9.  *
  10.  * bug reports, etc -> mab@cs.princeton.edu
  11.  *
  12.  * This version does NOT include the handle->name translation.
  13.  * That version works, but is rough enough that it is not included in
  14.  * the general distribution.  If you have a use for it, contact the author.
  15.  */
  16.  
  17. #include<sys/types.h>
  18. #include<sys/stat.h>
  19. #include <stdio.h>
  20. #include <strings.h>
  21. #include "nfsstuff.h"
  22.  
  23. #define HSIZE 65599
  24. #define MAXNF 20000
  25. static int nf=0;
  26. char comp[64] = "/usr/ucb/compress -c";
  27.  
  28. typedef struct clirec {
  29.     char name[64];    /* of client */
  30.     int direction;    /* 0==read, else write */
  31.     int zeroaccessed; /* zeroth byte accessed yet? */
  32.     int readcount;    /* total bytes accessed */
  33.     int writecount; /* bytes written */
  34.     unsigned long startsecs;    /* time operation started */
  35.     unsigned long startusecs;
  36.     unsigned long lastsecs;        /* last access */
  37.     unsigned long lastusecs;
  38.     struct clirec *nextcli;        /* in hash table */
  39.     struct clirec *nextpend, *prevpend; /* list of pending r/w ops */
  40.     struct file *file;
  41. } clirec;
  42.  
  43. typedef struct file {
  44.     char key[64];    /* server:handle */
  45.     int mode;
  46.     int uid;
  47.     int size;
  48.     struct clirec *clients;
  49.     struct file *next;
  50. } file;
  51.  
  52.  
  53. clirec *pending;    /* list of clients w/ pending read or write ops */
  54.  
  55. file *table[HSIZE];    /* the file handle hash table */
  56.  
  57. #define NAME "nfs.out"
  58.  
  59. int curfile=0;
  60. int cursecs=0;
  61. int curusecs=0;
  62. int lasttimedone=0;
  63. int oplen=135;
  64.  
  65. FILE *fd;
  66.  
  67. char *firstpart();
  68. char *lastpart();
  69. clirec *getcli();
  70. file *getfile();
  71. unsigned long hashval();
  72. char *mkkey();
  73. char *Malloc();
  74. static int n=1;
  75.  
  76.  
  77.  
  78.  
  79. int    nfs_null(),
  80.     nfs_getattr(),
  81.     nfs_setattr(),
  82.     nfs_root(),
  83.     nfs_lookup(),
  84.     nfs_readlink(),
  85.     nfs_read(),
  86.     nfs_writecache(),
  87.     nfs_write(),
  88.     nfs_creat(),
  89.     nfs_remove(),
  90.     nfs_rename(),
  91.     nfs_link(),
  92.     nfs_symlink(),
  93.     nfs_mkdir(),
  94.     nfs_rmdir(),
  95.     nfs_readdir(),
  96.     nfs_statfs();
  97.  
  98. int (*nfs_proc[])() = {
  99.         nfs_null,          /*  0 */
  100.     nfs_getattr,       /*  1 */
  101.         nfs_setattr,       /*  2 */
  102.         nfs_root,          /*  3 */
  103.         nfs_lookup,        /*  4 */
  104.         nfs_readlink,      /*  5 */
  105.         nfs_read,          /*  6 */
  106.         nfs_writecache,    /*  7 */
  107.         nfs_write,         /*  8 */
  108.         nfs_creat,         /*  9 */
  109.         nfs_remove,        /* 10 */
  110.         nfs_rename,        /* 11 */
  111.         nfs_link,          /* 12 */
  112.         nfs_symlink,       /* 13 */
  113.         nfs_mkdir,         /* 14 */
  114.         nfs_rmdir,         /* 15 */
  115.         nfs_readdir,       /* 16 */
  116.         nfs_statfs         /* 17 */
  117. };
  118.  
  119.  
  120. char template[64];
  121. int compress=0;
  122. int outflag=0;
  123. int filesize=5000;
  124.  
  125. main(argc,argv)
  126.      int argc;
  127.      char **argv;
  128. {
  129.     int i;
  130.     char *flag;
  131.     char *c;
  132.     char *pn;
  133.  
  134.     strcpy(template,NAME);
  135.     pn=argv[0];
  136.     while (--argc) {
  137.         if (**++argv == '-') {    /* flag */
  138.             for (flag = ++*argv; *flag; flag++) {
  139.                 switch (*flag) {
  140.                     case '-':    /* just write to stdout */
  141.                     outflag++;
  142.                     fd=stdout;
  143.                     break;
  144.                     case 'c':    /* compress output */
  145.                     compress++;
  146.                     break;
  147.                     case 's':    /* size of output files */
  148.                     case 't':    /* name template*/
  149.                     case 'n':    /* file number */
  150.                     case 'w':    /* time to wait for close */
  151.                     case 'z':    /* name of compress cmd */
  152.                     enq(*flag);
  153.                     break;
  154.                     default:
  155.                     usage(pn);
  156.                     exit(-1);
  157.                 }
  158.             }
  159.         } else {
  160.             switch (deq()) {
  161.                 case -1:
  162.                 usage();
  163.                 exit(-1);
  164.                 case 's':
  165.                 filesize=atoi(*argv);
  166.                 break;
  167.                 case 't':
  168.                 strcpy(template,*argv);
  169.                 break;
  170.                 case 'n':
  171.                 curfile=atoi(*argv);
  172.                 break;
  173.                 case 'w':
  174.                 oplen=atoi(*argv);
  175.                 break;
  176.                 case 'z':
  177.                 strcpy(comp,*argv);
  178.                 break;
  179.                 default:    /* should never happen */
  180.                 fprintf(stderr,"Internal error\n");
  181.                 exit(-2);
  182.             }
  183.         }
  184.  
  185.     }
  186.     if ((deq() != -1)) {
  187.         usage(pn);
  188.         exit(-1);
  189.     }
  190.     for (i=0; i<HSIZE; i++)
  191.         table[i]=NULL;
  192.     if (!outflag)
  193.         outopen();
  194.     yyparse();
  195.     cursecs+=500;
  196.     checkall();
  197. }
  198.  
  199.  
  200. usage(s)
  201.      char *s;
  202. {
  203.     fprintf(stderr,
  204.         "usage: %s [--] [-c] [-t template] [-s size] [-n seqnum] [-w timeout] [-z filt]\n",s);
  205. }
  206.  
  207.  
  208. #define QS 10
  209. struct {
  210.     int data[QS];
  211.     int head;
  212.     int tail;
  213. } argq = {{0},0,0};
  214.  
  215. enq(f)
  216.      char f;
  217. {
  218.     argq.tail++;
  219.     argq.tail %= QS;
  220.     if (argq.head==argq.tail) {
  221.         fprintf(stderr,"Can't deal with this\n");
  222.         exit(-2);
  223.     }
  224.     argq.data[argq.tail]=f;
  225. }
  226.  
  227. deq()
  228. {
  229.     if (argq.head==argq.tail)
  230.         return -1;
  231.     argq.head++;
  232.     argq.head %= QS;
  233.     return(argq.data[argq.head]);
  234. }
  235.  
  236. #define CHECKFREQ 65
  237.  
  238. outopen()
  239. {
  240.     char buf[64];
  241.     if (compress) {
  242.         sprintf(buf,"%s>%s.%05d.Z",comp,template,curfile);
  243.         if ((fd=popen(buf,"w")) == NULL) {
  244.             perror(buf);
  245.             exit(1);
  246.         }
  247.     } else {
  248.         sprintf(buf,"%s.%05d",template,curfile);
  249.         if((fd=fopen(buf,"w"))==NULL) {
  250.             perror(buf);
  251.             exit(1);
  252.         }
  253.     }
  254. }
  255.     
  256. do_operation()
  257. {
  258.     if (l.stat == 0)
  259.         return;    /* we dont care about failures */
  260.     if (l.op>=RFS_NPROC)
  261.         return; /* should never happen */
  262.     if (!validtime(l.time))
  263.         return;    /* should never happen */
  264.     cursecs=atoi(firstpart(l.time));
  265.     curusecs=atoi(lastpart(l.time));
  266.     if ((cursecs-lasttimedone)>CHECKFREQ) {
  267.         checkall();
  268.         lasttimedone=cursecs;
  269.     }
  270.     if (!outflag &&(n>filesize)) {
  271.         switchfile();
  272.         n=1;
  273.     }
  274.     (*nfs_proc[l.op])();
  275. }
  276.  
  277. switchfile()
  278. {
  279.     char buf[64];
  280.     
  281.     cursecs += 500;
  282.     checkall();
  283.     cursecs -= 500;
  284.     closefile(fd);
  285.     curfile++;
  286.     outopen();
  287. }
  288.  
  289. closefile()
  290. {
  291.     if (compress)
  292.         pclose(fd);
  293.     else
  294.         fclose(fd);
  295. }
  296.  
  297. validtime(s)
  298.      char *s;
  299. {
  300.     return (index(s,'.') != 0);
  301. }
  302.  
  303. char *firstpart(s)
  304.      char *s;
  305. {
  306.     static char buf[64];
  307.     strcpy(buf,s);
  308.     *(index(buf,'.'))='\0';
  309.     return buf;
  310. }
  311.  
  312. char *lastpart(s)
  313.      char *s;
  314. {
  315.     return(index(s,'.')+1);
  316. }
  317.  
  318.  
  319. unsigned long hashval(s)
  320.      char *s;
  321. {
  322.     unsigned long v;
  323.     int j;
  324.  
  325.     v=0;
  326.     j=0;
  327.     while (*s) {
  328.         if (j>20)
  329.             j=0;
  330.         v += (*s++)<<(j++);
  331.     }
  332.     return v%HSIZE;
  333. }
  334.  
  335.  
  336. checkall()
  337. {
  338.     clirec *c, *prev, *temp;
  339.     
  340.     c=pending;
  341.     prev=NULL;
  342.     while (c!=NULL) {
  343.         if (tooold(c)) {
  344.             emit(c);
  345.             temp=c->nextpend;
  346.             if (prev!=NULL) {
  347.                 prev->nextpend=c->nextpend;
  348.             } else
  349.                 pending = c->nextpend;
  350.             if (c->nextpend !=NULL)
  351.                 c->nextpend->prevpend = prev;
  352.             remove(c);    /* remove from parent list */
  353.             free(c);
  354.             c=temp;
  355.         } else {
  356.             prev=c;
  357.             c=c->nextpend;
  358.         }
  359.     }
  360. }
  361.  
  362. remove(c)
  363.      clirec *c;
  364. {
  365.     clirec *cl;
  366.  
  367.     cl=c->file->clients;
  368.     if (cl==c) {
  369.         c->file->clients = c->nextcli;
  370.         return;
  371.     }
  372.     while (cl) {
  373.         if (cl->nextcli == c) {
  374.             cl->nextcli = c->nextcli;
  375.             return;
  376.         }
  377.         cl=cl->nextcli;
  378.     }
  379. }
  380.  
  381.  
  382. tooold(c)
  383.      clirec *c;
  384. {
  385.     return ((cursecs - c->lastsecs)>oplen);
  386. }
  387.  
  388. readold(c)
  389.      clirec *c;
  390. {
  391.     if (c->writecount)
  392.         return 0;
  393.     return ((cursecs - c->lastsecs)>2);
  394. }
  395.  
  396.  
  397. file *getfile(s,h)
  398.      char *s;
  399.      char *h;
  400. {
  401.     char buf[64];
  402.     file *f;
  403.     clirec *c;
  404.     clirec *prev;
  405.     clirec *temp;
  406.     unsigned long hash;
  407.  
  408.     strcpy(buf,mkkey(s,h));
  409.     hash=hashval(buf);
  410.     f=table[hash];
  411.     while (f!=NULL) {
  412.         if (strcmp(f->key,buf)==0) {
  413.             /* first we check for old clients */
  414.             c=f->clients;
  415.             prev=NULL;
  416.             while (c) {
  417.                 if (tooold(c)) {
  418.                     emit(c);
  419.                     temp=c->nextcli;
  420.                     if (prev !=NULL)
  421.                         prev->nextcli = c->nextcli;
  422.                     else
  423.                         f->clients = c->nextcli;
  424.                     if (c->nextpend != NULL)
  425.                         c->nextpend->prevpend=
  426.                             c->prevpend;
  427.                     if (c->prevpend != NULL)
  428.                         c->prevpend->nextpend=
  429.                             c->nextpend;
  430.                     else
  431.                         pending=c->nextpend;
  432.                     free (c);
  433.                     c=temp;
  434.                 } else {
  435.                     prev=c;
  436.                     c=c->nextcli;
  437.                 }
  438.             }
  439.             return f;
  440.         }
  441.         f=f->next;
  442.     }
  443.     if ((f=(file *)Malloc(sizeof(file))) == NULL) {
  444.         perror("malloc");
  445.         exit(1);
  446.     }
  447.     nf++;
  448.     if (nf>MAXNF)
  449.         gc();
  450.     strcpy(f->key,buf);
  451.     f->mode=0;
  452.     f->uid=0;
  453.     f->size=0;
  454.     f->clients=NULL;
  455.     f->next=table[hash];
  456.     table[hash]=f;
  457.     return f;
  458. }
  459.  
  460. clirec *getcli(f,n)
  461.      file *f;
  462.      char *n;
  463. {
  464.     clirec *c;
  465.  
  466.     c=f->clients;
  467.     while (c!=NULL) {
  468.         if (strcmp(c->name,n)==0)
  469.             return c;
  470.         c=c->nextcli;
  471.     }
  472.     if ((c=(clirec *)Malloc(sizeof(clirec))) == NULL) {
  473.         perror("malloc");
  474.         exit(1);
  475.     }
  476.     strcpy(c->name,n);
  477.     c->lastusecs=c->startusecs=curusecs;
  478.     c->lastsecs=c->startsecs=cursecs;
  479.     c->readcount=0;
  480.     c->writecount=0;
  481.     c->zeroaccessed=0;
  482.     c->nextcli=f->clients;
  483.     f->clients=c;
  484.     c->nextpend=pending;
  485.     if (pending !=NULL)
  486.         pending->prevpend = c;
  487.     c->prevpend = NULL;
  488.     pending = c;
  489.     c->file=f;
  490.     return c;
  491. }
  492.  
  493.  
  494.  
  495. char *mkkey(c,h)
  496.      char *c;
  497.      char *h;
  498. {
  499.     static char buf[64];
  500.  
  501.     sprintf(buf,"%s:%s",c,h);
  502.     return buf;
  503. }
  504.  
  505.  
  506. emit(c)
  507.      clirec *c;
  508. {
  509.     fprintf(fd,"%d.%06d | %s | %s | %s | %d | %d\n",
  510.            c->startsecs,
  511.            c->startusecs,
  512.            (c->writecount?"write":"read"),
  513.            c->file->key,
  514.            c->name,
  515.            (c->writecount?c->writecount:c->readcount),
  516.            c->file->size?c->file->size:c->readcount);
  517.     n++;
  518. }
  519.  
  520. nfs_null()
  521. {
  522.     /* do nothing */
  523. }
  524.  
  525.  
  526. nfs_getattr()
  527. {
  528.     file *f;
  529.     clirec *c;
  530.     unsigned int mode;
  531.  
  532.     /* first, make sure this is a file */
  533.     sscanf(l.reply.mode,"%o",&mode);
  534.     if ((mode&S_IFMT) != S_IFREG)
  535.         return;
  536.     /* find or create a file record */
  537.     if ((f=getfile(l.svr,l.call.handle1)) == NULL)
  538.         exit(1); /* should never happen */
  539.     /* set up the file values */
  540.     f->uid = atoi(l.reply.uid);
  541.     f->mode = mode;
  542.     f->size = atoi(l.reply.size);
  543.     if ((c=getcli(f,l.cln)) == NULL)
  544.         exit(1);  /* should never happen */
  545.     c->lastsecs = cursecs;
  546.     c->lastusecs = curusecs;
  547. }
  548.  
  549. nfs_setattr()
  550. {
  551.     /* do a little; this might really be a write */
  552.     file *f;
  553.     clirec *c;
  554.     int size;
  555.     int mode;
  556.  
  557.     size=atoi(l.reply.size);
  558.     if (size<0)
  559.         return;
  560.     sscanf(l.reply.mode,"%o",&mode);
  561.     if ((mode&S_IFMT) != S_IFREG)
  562.         return;
  563.     /* the size changed, so now we treat as a write */
  564.     if ((f=getfile(l.svr,l.call.handle1)) == NULL)
  565.         exit(1); /* should never happen */
  566.     if ((c=getcli(f,l.cln)) == NULL)
  567.         exit(1);  /* should never happen */
  568.     if ((c->readcount>0) ||
  569.         readold(c))  {    /* there was a read pending on this file */
  570.         emit(c);
  571.         c->startsecs=cursecs;
  572.         c->startusecs=curusecs;
  573.         c->readcount=0;
  574.         c->zeroaccessed=0;
  575.     }
  576.     if (c->writecount && (size==0)) {
  577.         emit(c);
  578.         c->startsecs=cursecs;
  579.         c->startusecs = curusecs;
  580.         c->writecount=0;
  581.         c->zeroaccessed = 0;
  582.     }
  583.     f->size=size;
  584.     f->mode = mode;
  585.     f->uid = atoi(l.reply.uid);
  586.     c->writecount += 1;
  587.     c->lastusecs=curusecs;
  588.     c->lastsecs=cursecs;
  589. }
  590.  
  591. nfs_root()
  592. {
  593.     /* do nothing */
  594. }
  595.  
  596. nfs_readlink()
  597. {
  598.     /* do nothing */
  599. }
  600.  
  601. nfs_read()
  602. {
  603.     file *f;
  604.     clirec *c;
  605.     int count;
  606.  
  607.     if ((f=getfile(l.svr,l.call.handle1)) == NULL)
  608.         exit(1); /* should never happen */
  609.     if ((c=getcli(f,l.cln)) == NULL)
  610.         exit(1);  /* should never happen */
  611.     if (c->writecount>0) {    /* there was a write pending on this file */
  612.         /* make sure this is a positive read */
  613.         if (!(atoi(l.reply.count) < 0))
  614.             return;
  615.         emit(c);
  616.         c->startsecs=cursecs;
  617.         c->startusecs=curusecs;
  618.         c->writecount=0;
  619.         c->zeroaccessed=0;
  620.     }
  621.     if (atoi(l.call.offset)==0) {
  622.         if (c->zeroaccessed) {
  623.             emit(c);
  624.             c->startsecs=cursecs;
  625.             c->startusecs=curusecs;
  626.             c->readcount=0;
  627.         } else
  628.             c->zeroaccessed=1;
  629.     }
  630.     c->readcount += atoi(l.reply.count);
  631.     c->lastusecs=curusecs;
  632.     c->lastsecs=cursecs;
  633. }
  634.  
  635. nfs_writecache()
  636. {
  637.     /* do nothing */
  638. }
  639.  
  640.  
  641. nfs_write()
  642. {
  643.     file *f;
  644.     clirec *c;
  645.  
  646.     if ((f=getfile(l.svr,l.call.handle1)) == NULL)
  647.         exit(1); /* should never happen */
  648.     if ((c=getcli(f,l.cln)) == NULL)
  649.         exit(1);  /* should never happen */
  650.     if ((c->readcount>0) ||
  651.         readold(c))  {    /* there was a read pending on this file */
  652.         emit(c);
  653.         c->startsecs=cursecs;
  654.         c->startusecs=curusecs;
  655.         c->zeroaccessed=0;
  656.         c->readcount=0;
  657.     }
  658.     if (atoi(l.call.offset)==0) {
  659.         if (c->zeroaccessed) {
  660.             emit(c);
  661.             c->startsecs=cursecs;
  662.             c->startusecs=curusecs;
  663.             c->writecount=0;
  664.         } else
  665.             c->zeroaccessed=1;
  666.     }
  667.     c->writecount += atoi(l.call.count);
  668.     f->size = atoi(l.reply.size);
  669.     c->lastusecs=curusecs;
  670.     c->lastsecs=cursecs;
  671. }
  672.  
  673. nfs_creat()
  674. {
  675.     /* do very little */
  676. }
  677.  
  678. nfs_remove()
  679. {
  680.     /* do very little */
  681. }
  682.  
  683. nfs_rename()
  684. {
  685.     /* do nothing */
  686. }
  687.  
  688. nfs_lookup()
  689. {
  690.     file *f;
  691.     unsigned int mode;
  692.  
  693.     /* first, make sure this is a file */
  694.     sscanf(l.reply.mode,"%o",&mode);
  695.     if ((mode&S_IFMT) != S_IFREG)
  696.         return;
  697.     /* find or create a file record */
  698.     if ((f=getfile(l.svr,l.reply.handle)) == NULL)
  699.         exit(1); /* should never happen */
  700.     /* set up the file values */
  701.     f->uid = atoi(l.reply.uid);
  702.     f->mode = mode;
  703.     f->size = atoi(l.reply.size);
  704. }
  705.  
  706. nfs_link()
  707. {
  708.     /* do nothing */
  709. }
  710.  
  711. nfs_symlink()
  712. {
  713.     /* do nothing */
  714. }
  715.  
  716. nfs_mkdir()
  717. {
  718.     /* do nothing */
  719. }
  720.  
  721. nfs_rmdir()
  722. {
  723.     /* do nothing */
  724. }
  725.  
  726. nfs_readdir()
  727. {
  728.     /* do nothing */
  729. }
  730.  
  731. nfs_statfs()
  732. {
  733.     /* do nothing */
  734. }
  735.  
  736. char *Malloc(n)
  737.      int n;
  738. {
  739.     char *m;
  740.  
  741.     if ((m=(char *)malloc(n)) == NULL) {
  742.         gc();
  743.         return ((char *)malloc(n));
  744.     } else
  745.         return (m);
  746. }
  747.  
  748. gc()
  749. {
  750.     int i;
  751.     file *f;
  752.     file **prev;
  753.     int count=0;
  754.  
  755.     fprintf(fd,"#collecting garbage\n");
  756.     fflush(fd);
  757.     for (i=0; i<HSIZE; i++) {
  758.         f=table[i];
  759.         prev = &table[i];
  760.         while (f != NULL) {
  761.             if (f->clients == NULL) {
  762.                 *prev=f->next;
  763.                 free(f);
  764.                 f = *prev;
  765.                 count++;
  766.                 nf--;
  767.             } else {
  768.                 prev = &f->next;
  769.                 f= f->next;
  770.             }
  771.         }
  772.     }
  773.     fprintf(fd,"#GC Count=%d\n",count);
  774.     fflush(fd);
  775. }
  776.